home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / video / xevil-1.000 / xevil-1 / area.C < prev    next >
C/C++ Source or Header  |  1995-07-10  |  12KB  |  664 lines

  1. // "area.C"  
  2. // TAG: AR
  3. // Also has class Avoid.
  4.  
  5. /*    Copyright (C) 1994  Steve Hardt
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 1, or (at your option)
  10.     any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.     Steve Hardt 
  22.     hardts@athena.mit.edu hardts@media.mit.edu
  23.     hardts@r4002.3dem.bioch.bcm.tmc.edu
  24.     2043 McClendon
  25.     Houston, TX 77030
  26. */
  27.  
  28. #ifndef NO_PRAGMAS
  29. #pragma implementation "area.h"
  30. #endif
  31.  
  32.  
  33. // Include Files
  34. extern "C" {
  35. #include <stdlib.h> // For the abs() function.
  36. #include <limits.h> // For INT_MAX
  37. }
  38. #include <iostream.h>
  39. #include "utils.h"
  40. #include "coord.h"
  41. #include "area.h"
  42.  
  43.  
  44.  
  45. Size Area::operator - (const Area &other) const
  46. {
  47.   assert ((shape == AR_RECT) && (other.shape == AR_RECT));
  48.   return pos - other.pos;
  49. }
  50.  
  51.  
  52.  
  53. Boolean Area::operator == (const Area &other) const 
  54. {
  55.   assert(shape == AR_RECT && other.shape == AR_RECT);
  56.   
  57.   return pos == other.pos && size == other.size;
  58. }
  59.  
  60.  
  61.  
  62. Area::Area(ARshape sh,const Pos &p,const Size &s)
  63. {
  64.   assert(sh == AR_RECT);
  65.   
  66.   shape = AR_RECT;
  67.   pos = p;
  68.   size = s;
  69. }
  70.  
  71.  
  72.  
  73. void Area::get_rect(Pos &p,Size &s) const
  74. {
  75.   assert (shape == AR_RECT);
  76.   p = pos;
  77.   s = size;
  78. }
  79.  
  80.  
  81.  
  82. Box Area::get_box() const
  83. {
  84.   assert (shape == AR_RECT);
  85.  
  86.   Loc loc;
  87.   loc.r = (int)floor(pos.y * WSQUARE_HEIGHT_INV);
  88.   loc.c = (int)floor(pos.x * WSQUARE_WIDTH_INV);
  89.  
  90.   // Always has dimension of at least 1x1.
  91.   Loc finish;
  92.   finish.r = (int)ceil((pos.y + size.height) * WSQUARE_HEIGHT_INV);
  93.   finish.c = (int)ceil((pos.x + size.width) * WSQUARE_WIDTH_INV);
  94.   
  95.   Dim dim(finish.r - loc.r,finish.c - loc.c);
  96.   
  97.   Box box(loc,dim);
  98.   return box;
  99. }
  100.  
  101.  
  102.  
  103. void Area::wsquares(Loc list[AR_WSQUARES_MAX],int &nitems) const
  104. {
  105.   nitems = 0;
  106.  
  107.   assert(shape == AR_RECT);
  108.   Loc loc;
  109.   for (loc.r = (int)floor(pos.y * WSQUARE_HEIGHT_INV);
  110.        loc.r * WSQUARE_HEIGHT < pos.y + size.height;
  111.        loc.r++)
  112.     for (loc.c = (int)floor(pos.x * WSQUARE_WIDTH_INV);
  113.      loc.c * WSQUARE_WIDTH < pos.x + size.width;
  114.      loc.c++)
  115.       {
  116.     if (nitems >= AR_WSQUARES_MAX)
  117.       {
  118. //        cerr << "Warning: Area:wsquares: Too many wsquares." << endl;
  119.         return;
  120.       }
  121.     list[nitems] = loc;
  122.     nitems++;
  123.       }
  124. }
  125.  
  126.  
  127.  
  128. Boolean Area::overlap(const Area &r) const
  129. {
  130.   assert((shape == AR_RECT) && (r.shape == AR_RECT));
  131.  
  132.   if ((pos.x + size.width <= r.pos.x) ||
  133.       (r.pos.x + r.size.width <= pos.x) ||
  134.       (pos.y + size.height <= r.pos.y) ||
  135.       (r.pos.y + r.size.height <= pos.y))
  136.     return False;
  137.   else
  138.     return True;
  139. }
  140.  
  141.  
  142.  
  143. Boolean Area::overlap(const Loc &loc) const
  144. {
  145.   Pos test;
  146.   Boolean ret;
  147.  
  148.   assert(shape == AR_RECT);
  149.   
  150.   test.x = loc.c * WSQUARE_WIDTH;
  151.   test.y = loc.r * WSQUARE_HEIGHT;
  152.  
  153.   if ((test.x >= pos.x + size.width) || (test.y >= pos.y + size.height) ||
  154.       (test.x + WSQUARE_WIDTH <= pos.x) || (test.y + WSQUARE_HEIGHT <= pos.y))
  155.     ret = False;
  156.   else
  157.     ret = True;
  158.  
  159.   return ret;
  160. }
  161.  
  162.  
  163.  
  164. Boolean Area::overlap(const Box &box) const
  165. {
  166.   Pos testPos;
  167.   Size testSize;
  168.   Boolean ret;
  169.  
  170.   assert(shape == AR_RECT);
  171.   
  172.   testPos.x = box.loc.c * WSQUARE_WIDTH;
  173.   testPos.y = box.loc.r * WSQUARE_HEIGHT;
  174.   testSize.width = box.dim.colMax * WSQUARE_WIDTH;
  175.   testSize.height = box.dim.rowMax * WSQUARE_HEIGHT;
  176.  
  177.   if ((testPos.x >= pos.x + size.width) || 
  178.       (testPos.y >= pos.y + size.height) ||
  179.       (testPos.x + testSize.width <= pos.x) || 
  180.       (testPos.y + testSize.height <= pos.y))
  181.     ret = False;
  182.   else
  183.     ret = True;
  184.   
  185.   return ret;
  186. }
  187.  
  188.  
  189.  
  190. Boolean Area::overlap(const Pos &p) const
  191. {
  192.   assert(shape == AR_RECT);
  193.  
  194.   if ((pos.x + size.width <= p.x) ||
  195.       (pos.x > p.x) ||
  196.       (pos.y + size.height <= p.y) ||
  197.       (pos.y > p.y))
  198.       return False;
  199.   else
  200.     return True;
  201. }
  202.  
  203.  
  204.  
  205. Loc Area::middle_wsquare() const
  206. {
  207.   assert (shape == AR_RECT);
  208.  
  209.   Loc ret;
  210.   ret.r = (int)floor((pos.y + size.height * 0.5) * WSQUARE_HEIGHT_INV);
  211.   ret.c = (int)floor((pos.x + size.width * 0.5) * WSQUARE_WIDTH_INV);
  212.   return ret;
  213. }
  214.  
  215.  
  216.  
  217. ARsig Area::avoid_wsquare(Avoid &avoid,const Loc &loc) const
  218. {
  219.   assert(shape == AR_RECT);
  220.   
  221.   if (! overlap(loc))
  222.     return AR_NO_SIG;
  223.  
  224.   avoid.r = -(loc.c * WSQUARE_WIDTH - size.width - pos.x);
  225.   avoid.dn = -(loc.r * WSQUARE_HEIGHT - size.height - pos.y);
  226.   avoid.l = (loc.c + 1) * WSQUARE_WIDTH - pos.x;
  227.   avoid.up = (loc.r + 1) * WSQUARE_HEIGHT - pos.y;
  228.   
  229.   return AR_CLOSE;
  230. }
  231.  
  232.  
  233.  
  234. int Area::avoid_wsquare_dir(const Loc &loc,Dir dir) const
  235. {
  236.   assert(shape == AR_RECT);
  237.   assert(overlap(loc));
  238.  
  239.   switch (dir) {
  240.   case CO_R:
  241.     return (loc.c + 1) * WSQUARE_WIDTH - pos.x;
  242.   case CO_DN:
  243.     return (loc.r + 1) * WSQUARE_HEIGHT - pos.y;
  244.   case CO_L:
  245.     return -(loc.c * WSQUARE_WIDTH - size.width - pos.x);
  246.   case CO_UP:
  247.     return -(loc.r * WSQUARE_HEIGHT - size.height - pos.y);
  248.   };
  249.  
  250.   assert(0);
  251.   return CO_air;
  252. }
  253.  
  254.  
  255.  
  256. Size Area::avoid(const Area &other) const
  257. {
  258.   assert((shape == AR_RECT) && (other.shape == AR_RECT));
  259.  
  260.   Avoid avoid;
  261.   avoid.r = -(other.pos.x  - size.width - pos.x);
  262.   avoid.dn = -(other.pos.y - size.height - pos.y);
  263.   avoid.l = other.pos.x + other.size.width - pos.x;
  264.   avoid.up = other.pos.y + other.size.height - pos.y;
  265.  
  266.   return avoid.offset_rank();
  267. }
  268.  
  269.  
  270.  
  271. Size Area::avoid_no_up(const Area &other) const
  272. {
  273.   assert((shape == AR_RECT) && (other.shape == AR_RECT));
  274.  
  275.   Avoid avoid;
  276.   avoid.r = -(other.pos.x  - size.width - pos.x);
  277.   avoid.dn = INT_MAX;
  278.   avoid.l = other.pos.x + other.size.width - pos.x;
  279.   avoid.up = other.pos.y + other.size.height - pos.y;
  280.  
  281.   return avoid.offset_rank();
  282. }
  283.  
  284.  
  285.  
  286. Pos Area::adjacent_rect(const Size &otherSize,Dir dir) const
  287. {
  288.   assert (shape == AR_RECT);
  289.  
  290.   Pos middle = get_middle();
  291.   Pos ret;
  292.  
  293.   switch (dir) {
  294.   case CO_UP_R_R:
  295.   case CO_R:
  296.   case CO_DN_R_R:
  297.     ret.x = pos.x + size.width;
  298.     ret.y = middle.y - (int)(0.5 * otherSize.height);
  299.     break;
  300.   case CO_DN_R:
  301.     ret = pos + size;
  302.     break;
  303.   case CO_DN_DN_R:
  304.   case CO_DN:
  305.   case CO_DN_DN_L:
  306.     ret.x = middle.x - (int)(0.5 * otherSize.width);
  307.     ret.y = pos.y + size.height;
  308.     break;
  309.   case CO_DN_L:
  310.     ret.x = pos.x - otherSize.width;
  311.     ret.y = pos.y + size.height;
  312.     break;
  313.   case CO_DN_L_L:
  314.   case CO_L:
  315.   case CO_UP_L_L:
  316.     ret.x = pos.x - otherSize.width;
  317.     ret.y = middle.y - (int)(0.5 * otherSize.height);
  318.     break;
  319.   case CO_UP_L:
  320.     ret = pos - otherSize;
  321.     break;
  322.   case CO_UP_UP_L:
  323.   case CO_UP:
  324.   case CO_UP_UP_R:
  325.     ret.x = middle.x - (int)(0.5 * otherSize.width);
  326.     ret.y = pos.y - otherSize.height;
  327.     break;
  328.   case CO_UP_R:
  329.     ret.x = pos.x + size.width;
  330.     ret.y = pos.y - otherSize.height;
  331.     break;
  332.   default: 
  333.     assert(0);
  334.     break;
  335.   };
  336.  
  337.   return ret;
  338. }
  339.  
  340.  
  341.  
  342. Pos Area::get_middle() const
  343. {
  344.   assert(shape == AR_RECT);
  345.  
  346.   Pos ret(pos.x + (int)floor(size.width * 0.5),
  347.       pos.y + (int)floor(size.height * 0.5));
  348.   return ret;
  349. }
  350.  
  351.  
  352.  
  353. void Area::touching_wsquares(TouchingList &list) const
  354. {
  355.   assert(shape == AR_RECT);
  356.   
  357.   list.r.num = list.dn.num = list.l.num = list.up.num = 0;
  358.   
  359.   // Right side.
  360.   if ((pos.x + size.width) % WSQUARE_WIDTH == 0)
  361.     {
  362.       Loc loc;
  363.       loc.c = (pos.x + size.width) / WSQUARE_WIDTH;
  364.       
  365.       for (loc.r = (int)floor(pos.y * WSQUARE_HEIGHT_INV);
  366.        loc.r * WSQUARE_HEIGHT < pos.y + size.height;
  367.        loc.r++)
  368.     {
  369.       list.r.list[list.r.num] = loc;
  370.       list.r.num++;
  371.     }
  372.     }
  373.  
  374.   // Bottom.
  375.   if ((pos.y + size.height) % WSQUARE_HEIGHT == 0)
  376.     {
  377.       Loc loc;
  378.       loc.r = (pos.y + size.height) / WSQUARE_HEIGHT;
  379.       
  380.       for (loc.c = (int)floor(pos.x * WSQUARE_WIDTH_INV);
  381.        loc.c * WSQUARE_WIDTH < pos.x + size.width;
  382.        loc.c++)
  383.     {
  384.       list.dn.list[list.dn.num] = loc;
  385.       list.dn.num++;
  386.     }
  387.     }
  388.  
  389.   // Left side.
  390.   if (pos.x % WSQUARE_WIDTH == 0)
  391.     {
  392.       Loc loc;
  393.       loc.c = pos.x / WSQUARE_WIDTH - 1;
  394.       
  395.       for (loc.r = (int)floor(pos.y * WSQUARE_HEIGHT_INV);
  396.        loc.r * WSQUARE_HEIGHT < pos.y + size.height;
  397.        loc.r++)
  398.     {
  399.       list.l.list[list.l.num] = loc;
  400.       list.l.num++;
  401.     }
  402.     }
  403.  
  404.   // Top.
  405.   if (pos.y % WSQUARE_HEIGHT == 0)
  406.     {
  407.       Loc loc;
  408.       loc.r = pos.y / WSQUARE_HEIGHT - 1;
  409.       
  410.       for (loc.c = (int)floor(pos.x * WSQUARE_WIDTH_INV);
  411.        loc.c * WSQUARE_WIDTH < pos.x + size.width;
  412.        loc.c++)
  413.     {
  414.       list.up.list[list.up.num] = loc;
  415.       list.up.num++;
  416.     }
  417.     }
  418. }
  419.  
  420.  
  421.  
  422. void Area::set_middle(const Pos &mid)
  423. {
  424.   assert(shape == AR_RECT);
  425.  
  426.   pos.x = mid.x - (int)floor(size.width * 0.5);
  427.   pos.y = mid.y - (int)floor(size.height * 0.5);
  428. }
  429.  
  430.  
  431.  
  432. Dir Area::dir_to(const Pos &other) const
  433. {
  434.   assert(shape == AR_RECT);
  435.  
  436.   int xdir,ydir;
  437.  
  438.   if (other.x >= pos.x + size.width)
  439.     xdir = 1;
  440.   else if (other.x < pos.x)
  441.     xdir = -1;
  442.   else
  443.     xdir = 0;
  444.  
  445.   if (other.y >= pos.y + size.height)
  446.     ydir = 1;
  447.   else if (other.y < pos.y)
  448.     ydir = -1;
  449.   else
  450.     ydir = 0;
  451.  
  452.   switch (xdir) {
  453.   case 1:
  454.     switch (ydir) {
  455.     case -1:
  456.       return CO_UP_R;
  457.     case 0:
  458.       return CO_R;
  459.     case 1:
  460.       return CO_DN_R;
  461.     };
  462.   case 0:
  463.     switch (ydir) {
  464.     case -1:
  465.       return CO_UP;
  466.     case 0:
  467.       return CO_air;
  468.     case 1:
  469.       return CO_DN;
  470.     };
  471.   case -1:
  472.     switch (ydir) {
  473.     case -1:
  474.       return CO_UP_L;
  475.     case 0:
  476.       return CO_L;
  477.     case 1:
  478.       return CO_DN_L;
  479.     };
  480.   };
  481.  
  482.   assert(0);
  483.   return CO_air;
  484. }
  485.  
  486.  
  487.  
  488. Dir Area::dir_to(const Area &other) const
  489. {
  490.   assert((shape == AR_RECT) && (other.shape == AR_RECT));
  491.  
  492.   int xdir,ydir;
  493.  
  494.   if (other.pos.x >= pos.x + size.width)
  495.     xdir = 1;
  496.   else if (other.pos.x + other.size.width <= pos.x)
  497.     xdir = -1;
  498.   else
  499.     xdir = 0;
  500.  
  501.   if (other.pos.y >= pos.y + size.height)
  502.     ydir = 1;
  503.   else if (other.pos.y + other.size.height <= pos.y)
  504.     ydir = -1;
  505.   else
  506.     ydir = 0;
  507.  
  508.   switch (xdir) {
  509.   case 1:
  510.     switch (ydir) {
  511.     case -1:
  512.       return CO_UP_R;
  513.     case 0:
  514.       return CO_R;
  515.     case 1:
  516.       return CO_DN_R;
  517.     };
  518.   case 0:
  519.     switch (ydir) {
  520.     case -1:
  521.       return CO_UP;
  522.     case 0:
  523.       return CO_air;
  524.     case 1:
  525.       return CO_DN;
  526.     };
  527.   case -1:
  528.     switch (ydir) {
  529.     case -1:
  530.       return CO_UP_L;
  531.     case 0:
  532.       return CO_L;
  533.     case 1:
  534.       return CO_DN_L;
  535.     };
  536.   };
  537.  
  538.   assert(0);
  539.   return CO_air;
  540. }
  541.  
  542.  
  543.  
  544. Area Area::combine(const Area &a) const
  545. {
  546.   Pos pos1;
  547.   pos1.x = min(pos.x,a.pos.x);
  548.   pos1.y = min(pos.y,a.pos.y);
  549.  
  550.   Pos pos2;
  551.   pos2.x = max(pos.x + size.width,a.pos.x + a.size.width);
  552.   pos2.y = max(pos.y + size.height,a.pos.y + a.size.height);
  553.  
  554.   Size s = pos2 - pos1;
  555.  
  556.   Area ret(AR_RECT,pos1,s);
  557.   return ret;
  558. }
  559.  
  560.  
  561.  
  562.  
  563. /////////////////////////////// Avoid ///////////////////////////////////////
  564. void Avoid::maximize(const Avoid &avoid)
  565. {
  566.   r = max(r,avoid.r);
  567.   dn = max(dn,avoid.dn);
  568.   l = max(l,avoid.l);
  569.   up = max(up,avoid.up);
  570. }
  571.  
  572.  
  573.  
  574. Size Avoid::offset_rank(int rank) const
  575. {
  576.   assert ((rank >= 0) && (rank < 4));
  577.  
  578.   int dists[4];
  579.   dists[0] = r;
  580.   dists[1] = dn;
  581.   dists[2] = l;
  582.   dists[3] = up;
  583.   Utils::insertionSort(dists,4);
  584.   int m = dists[rank];      
  585.   
  586.   Size ret;
  587.   if (m == r)
  588.     {
  589.       ret.width = -r;
  590.       ret.height = 0;
  591.       return ret;
  592.     }
  593.   if (m == dn)
  594.     {
  595.       ret.width = 0;
  596.       ret.height = -dn;
  597.       return ret;
  598.     }
  599.   if (m == l)
  600.     {
  601.       ret.width = l;
  602.       ret.height = 0;
  603.       return ret;
  604.     }
  605.   if (m == up)
  606.     {
  607.       ret.width = 0;
  608.       ret.height = up;
  609.       return ret;
  610.     }
  611.   assert(0);
  612.   ret.width = ret.height = 0;
  613.   return ret;
  614. }
  615.  
  616.  
  617.  
  618. Size Avoid::offset_dir(Dir dir) const
  619. {
  620.   Size ret;
  621.   switch(dir)
  622.     {
  623.     case CO_R:
  624.       ret.width = -r;
  625.       ret.height = 0;
  626.       break;
  627.     case CO_DN:
  628.       ret.width = 0;
  629.       ret.height = -dn;
  630.       break;
  631.     case CO_L:
  632.       ret.width = l;
  633.       ret.height = 0;
  634.       break;
  635.     case CO_UP:
  636.       ret.width = 0;
  637.       ret.height = up;
  638.       break;
  639.     default:
  640.       assert(0);
  641.     };
  642.   return ret;
  643. }
  644.  
  645.  
  646.  
  647. int Avoid::get_dir(Dir dir) const
  648. {
  649.   switch (dir) {
  650.   case CO_R:
  651.     return r;
  652.   case CO_DN:
  653.     return dn;
  654.   case CO_L:
  655.     return l;
  656.   case CO_UP:
  657.     return up;
  658.   };
  659.   assert(0);
  660.   return CO_air;
  661. }
  662.  
  663.  
  664.